import path from 'node:path';

import cors from '@koa/cors';
import Router from '@koa/router';
import Koa from 'koa';
import bodyParser from 'koa-bodyparser';

import { log } from '../logger';
import { toKebabCase } from '../utils/stringUtils';
import handlerAdapter from './handlerAdapter';
import { discoverApiModules } from './loader';

// 可以考虑将端口号放入配置或环境变量
const HTTP_PORT = process.env.VITE_HTTP_PORT
  ? parseInt(process.env.VITE_HTTP_PORT, 10)
  : process.env.HTTP_PORT
    ? parseInt(process.env.HTTP_PORT, 10)
    : 3100; // 优先读取 VITE_HTTP_PORT，其次是 HTTP_PORT，最后默认 3100

export class HttpServer {
  private app: Koa;
  private router: Router;
  private registeredRoutes = new Set<string>();

  constructor() {
    this.app = new Koa();
    this.router = new Router();

    log.info('[HttpServer] Initializing...');
    this._setupMiddleware();
    this._registerHttpRoutes();
    this._startServer();
  }

  private _setupMiddleware(): void {
    log.info('[HttpServer] Setting up middleware...');
    // 允许跨域请求 (根据需要调整配置)
    this.app.use(cors({ origin: '*' })); // 生产环境应配置更严格的 origin
    // 解析请求体
    this.app.use(bodyParser());
    // 加载路由
    this.app.use(this.router.routes()).use(this.router.allowedMethods());
    log.info('[HttpServer] Middleware setup complete.');
  }

  private _registerHttpRoutes(): void {
    log.info('[HttpServer] Starting to register HTTP routes from API modules...');
    const discoveredModules = discoverApiModules();
    let routesRegisteredCount = 0;

    if (discoveredModules.length === 0) {
      log.info('[HttpServer] No API modules found by loader to process for HTTP routes.');
      return;
    }

    log.info(`[HttpServer] Processing ${discoveredModules.length} discovered modules for HTTP routes...`);

    const prefixToRemove = '../../api/';

    for (const { path: relativePath, module } of discoveredModules) {
      let channelPrefix: string | undefined;

      if (relativePath.startsWith(prefixToRemove)) {
        const corePath = relativePath.substring(prefixToRemove.length);
        const parsed = path.parse(corePath.replace(/\\/g, '/'));
        const dirParts = parsed.dir ? parsed.dir.split('/') : [];
        const filePart = parsed.name;
        channelPrefix = ['api', ...dirParts, filePart]
          .filter((part) => part)
          .map(toKebabCase)
          .join('/');
        log.debug(`[HttpServer] Calculated channel prefix for ${relativePath}: ${channelPrefix}`);
      } else {
        log.warn(
          `[HttpServer] Module path ${relativePath} does not start with expected prefix '${prefixToRemove}'. Skipping.`
        );
        continue;
      }

      let moduleHandled = false;
      let moduleRegisteredCount = 0;

      if (module.handlers && typeof module.handlers === 'object') {
        const handlersObject = module.handlers as Record<string, (...args: any[]) => Promise<any>>;
        log.debug(
          `[HttpServer] Found 'handlers' object (Pattern A) from ${relativePath}. Processing entries for HTTP...`
        );

        for (const key in handlersObject) {
          if (Object.prototype.hasOwnProperty.call(handlersObject, key)) {
            const businessFunc = handlersObject[key];
            if (typeof businessFunc === 'function') {
              const operationName = toKebabCase(key);
              const channel = `${channelPrefix}/${operationName}`;
              const routePath = `/${channel}`;

              if (this._createKoaRoute('post', routePath, channel, businessFunc)) {
                routesRegisteredCount++;
                moduleRegisteredCount++;
              }
            } else {
              log.warn(
                `[HttpServer] Exported handler for key "${key}" in 'handlers' object from ${relativePath} is not a function. Skipping.`
              );
            }
          }
        }
        if (moduleRegisteredCount > 0) {
          log.info(
            `[HttpServer] Registered ${moduleRegisteredCount} HTTP routes from 'handlers' object in ${relativePath}`
          );
        } else {
          log.warn(
            `[HttpServer] Found 'handlers' object in ${relativePath}, but no valid functions were registered for HTTP.`
          );
        }
        moduleHandled = true;
      }

      if (!moduleHandled) {
        log.debug(`[HttpServer] Checking for individual function exports (Pattern B) from ${relativePath} for HTTP...`);
        let individualFuncRegisteredCount = 0;
        for (const exportKey in module) {
          if (
            Object.prototype.hasOwnProperty.call(module, exportKey) &&
            exportKey !== 'default' &&
            !exportKey.startsWith('_') &&
            typeof module[exportKey] === 'function'
          ) {
            const businessFunc = module[exportKey] as (...args: any[]) => Promise<any>;
            const operationName = toKebabCase(exportKey);
            const channel = `${channelPrefix}/${operationName}`;
            const routePath = `/${channel}`;

            if (this._createKoaRoute('post', routePath, channel, businessFunc)) {
              routesRegisteredCount++;
              individualFuncRegisteredCount++;
            }
          }
        }
        if (individualFuncRegisteredCount > 0) {
          log.info(
            `[HttpServer] Registered ${individualFuncRegisteredCount} HTTP routes from individual function exports in ${relativePath}`
          );
          moduleHandled = true;
        }
      }
    }

    log.info(`[HttpServer] Finished processing modules. Total HTTP routes registered: ${routesRegisteredCount}.`);
    log.debug('[HttpServer] Registered HTTP routes:', Array.from(this.registeredRoutes).sort());
  }

  private _createKoaRoute(
    method: 'post',
    routePath: string,
    channelName: string,
    businessFunc: (...args: any[]) => Promise<any>
  ): boolean {
    if (this.registeredRoutes.has(routePath)) {
      log.error(
        `[HttpServer] Duplicate HTTP route registration detected for "${method.toUpperCase()} ${routePath}" (channel: "${channelName}"). Registration skipped.`
      );
      return false;
    }

    try {
      log.info(`[HttpServer] Registering ${method.toUpperCase()} route: ${routePath} (channel: "${channelName}")`);
      this.router[method](routePath, async (ctx: Koa.Context) => {
        const args = ctx.request.body ? (Array.isArray(ctx.request.body) ? ctx.request.body : [ctx.request.body]) : [];
        log.debug(`[HttpServer] Route ${routePath} (channel: "${channelName}") invoked with body:`, ctx.request.body);

        // 使用通用响应处理器
        const response = await handlerAdapter.execute(businessFunc, args, {
          routePath,
          type: 'http'
        });

        // 设置HTTP状态码
        if (!response.success && response.code) {
          ctx.status = response.code;
        }

        ctx.body = response;
        log.debug(`[HttpServer] Route ${routePath} (channel: "${channelName}") executed successfully. Result sent.`);
      });
      this.registeredRoutes.add(routePath);
      return true;
    } catch (error) {
      log.error(
        `[HttpServer] Failed to register ${method.toUpperCase()} route ${routePath} (channel: "${channelName}"):`,
        error
      );
      return false;
    }
  }

  private _startServer(): void {
    this.app.on('error', (err, ctx) => {
      log.error('[HttpServer] Server error:', err, ctx);
      // 可以根据需要添加更详细的错误处理
    });

    this.app.listen(HTTP_PORT, '127.0.0.1', () => {
      log.info(`[HttpServer] Server listening on http://127.0.0.1:${HTTP_PORT}`);
    });
  }
}
